From 99bf801eac19a487de63fa9ebba9321974644cf8 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 24 May 2007 10:46:57 +0100 Subject: [PATCH] linux: Fix mem= kernel parameter when it is smaller than initial memory allocation. From: Chris Lalancette Signed-off-by: Keir Fraser --- .../arch/i386/kernel/setup-xen.c | 29 ++++++++++++++++++- .../arch/x86_64/kernel/setup-xen.c | 29 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c index 15cd36142f..f355f9a229 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c @@ -1583,6 +1583,7 @@ void __init setup_arch(char **cmdline_p) int i, j, k, fpp; struct physdev_set_iopl set_iopl; unsigned long max_low_pfn; + unsigned long p2m_pages; /* Force a quick death if the kernel panics (not domain 0). */ extern int panic_timeout; @@ -1725,6 +1726,32 @@ void __init setup_arch(char **cmdline_p) find_smp_config(); #endif + p2m_pages = max_pfn; + if (xen_start_info->nr_pages > max_pfn) { + /* + * the max_pfn was shrunk (probably by mem= or highmem= + * kernel parameter); shrink reservation with the HV + */ + struct xen_memory_reservation reservation = { + .address_bits = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + unsigned int difference; + int ret; + + difference = xen_start_info->nr_pages - max_pfn; + + set_xen_guest_handle(reservation.extent_start, + ((unsigned long *)xen_start_info->mfn_list) + max_pfn); + reservation.nr_extents = difference; + ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &reservation); + BUG_ON (ret != difference); + } + else if (max_pfn > xen_start_info->nr_pages) + p2m_pages = xen_start_info->nr_pages; + /* Make sure we have a correctly sized P->M table. */ if (!xen_feature(XENFEAT_auto_translated_physmap)) { phys_to_machine_mapping = alloc_bootmem_low_pages( @@ -1733,7 +1760,7 @@ void __init setup_arch(char **cmdline_p) max_pfn * sizeof(unsigned long)); memcpy(phys_to_machine_mapping, (unsigned long *)xen_start_info->mfn_list, - xen_start_info->nr_pages * sizeof(unsigned long)); + p2m_pages * sizeof(unsigned long)); free_bootmem( __pa(xen_start_info->mfn_list), PFN_PHYS(PFN_UP(xen_start_info->nr_pages * diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c index 2e6552859e..74e8fd6363 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -792,6 +792,33 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_XEN { int i, j, k, fpp; + unsigned long p2m_pages; + + p2m_pages = end_pfn; + if (xen_start_info->nr_pages > end_pfn) { + /* + * the end_pfn was shrunk (probably by mem= or highmem= + * kernel parameter); shrink reservation with the HV + */ + struct xen_memory_reservation reservation = { + .address_bits = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + unsigned int difference; + int ret; + + difference = xen_start_info->nr_pages - end_pfn; + + set_xen_guest_handle(reservation.extent_start, + ((unsigned long *)xen_start_info->mfn_list) + end_pfn); + reservation.nr_extents = difference; + ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &reservation); + BUG_ON (ret != difference); + } + else if (end_pfn > xen_start_info->nr_pages) + p2m_pages = xen_start_info->nr_pages; if (!xen_feature(XENFEAT_auto_translated_physmap)) { /* Make sure we have a large enough P->M table. */ @@ -801,7 +828,7 @@ void __init setup_arch(char **cmdline_p) end_pfn * sizeof(unsigned long)); memcpy(phys_to_machine_mapping, (unsigned long *)xen_start_info->mfn_list, - xen_start_info->nr_pages * sizeof(unsigned long)); + p2m_pages * sizeof(unsigned long)); free_bootmem( __pa(xen_start_info->mfn_list), PFN_PHYS(PFN_UP(xen_start_info->nr_pages * -- 2.30.2